/////precompiled////////
#include "precompiled.h"
////////////////////////


#include "svl_TWindow.h"
#include "svl_TCommand.h"

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
using namespace svl;

// TWindow ////////////////////////////////////////////////////////////////////

char TWindow::className[100];
::WNDCLASS TWindow::wndClass;
bool TWindow::isFirst = true;

//
TWindow::TWindow()    
{                    
  isModal = false;
  isMain = isFirst; isFirst = false;

  if (isMain)                  
  {
    ::lstrcpy(className,typeid(*this).name());

    wndClass.lpszClassName = className;
    wndClass.hInstance     = ::GetModuleHandle(NULL);
    wndClass.lpfnWndProc   = WndProc;
    wndClass.hCursor       = NULL;//LoadCursor(NULL,IDC_ARROW);
    wndClass.hIcon         = NULL;
    wndClass.lpszMenuName  = NULL;
    wndClass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
    wndClass.style         = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = 0;

    ::RegisterClass(&wndClass);
  }
                                
  hWnd = ::CreateWindowEx
  (
   (isMain ? WS_EX_APPWINDOW : WS_EX_TOOLWINDOW),
    className,
    "window",

    WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX
    |(isMain ? WS_MAXIMIZEBOX : 0)
    |(isMain ? WS_MINIMIZEBOX : 0)
    |WS_CLIPCHILDREN|WS_CLIPSIBLINGS,

    0,0,0,0,
    NULL,NULL,::GetModuleHandle(NULL),this
  );
}

//
TWindow::~TWindow()
{
  ::DestroyWindow(hWnd); if (isMain) {
    ::UnregisterClass(className,::GetModuleHandle(NULL));
  }
}

//
void TWindow::SetParent(HWND Parent) 
{ 
  ::SetWindowLong(Handle(),GWL_EXSTYLE,0);
  ::SetWindowLong(Handle(),GWL_STYLE,WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS /*|WS_CAPTION|WS_SYSMENU*/   /*|WS_BORDER*/);
  ::SetParent(Handle(),Parent); 
}

//
void TWindow::ShowModal() 
{
  MSG msg = { 0 };
  HWND WActive = ::GetActiveWindow();
          
  ::ShowWindow(hWnd,SW_SHOW);

  isModal = true;
  ::EnumThreadWindows(::GetCurrentThreadId(),&DisableWindows,(LPARAM)this);

  while (::GetMessage(&msg, NULL, 0, 0))
  {
    ::TranslateMessage(&msg);
    ::DispatchMessage(&msg);
    if (!isModal) { break;}
  }
  ::ShowWindow(hWnd,SW_HIDE);
  ::EnumThreadWindows(::GetCurrentThreadId(),&EnableWindows,(LPARAM)this);
  ::SetActiveWindow(WActive);
}

//  
void TWindow::Show()
{
  ::ShowWindow(hWnd,SW_SHOW);
}

//
void TWindow::Hide() 
{ 
  if (isModal) { isModal = false;} 
  else         { ::ShowWindow(hWnd,SW_HIDE);} 
}

//
int TWindow::MessagesLoop()
{
  MSG msg = { 0 }; while (::GetMessage(&msg, NULL, 0, 0)) 
	{
    //if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
 	
	  ::TranslateMessage(&msg);
	  ::DispatchMessage (&msg);
  }
  Hide();
  return (int) msg.wParam;
}

//
LRESULT TWindow::TWindow_WndProc(TMessage &Message)
{
  switch (Message.Msg)
  {
    case WM_CLOSE:
    {
      if (isMain) { ::PostQuitMessage(0);} 
      else        { Hide();}    
    }
    return 0; // not destroy
  }
  return ::DefWindowProc(hWnd,Message.Msg,Message.WParam,Message.LParam);
}

//
LRESULT CALLBACK TWindow::WndProc(HWND HWnd,UINT Msg,WPARAM WParam,LPARAM LParam)
{
  TWindow *Window = (TWindow*)::GetWindowLong(HWnd,GWL_USERDATA);

  switch (Msg)
  {
    case WM_CREATE:
      ::SetWindowLong(HWnd,GWL_USERDATA,(long)((CREATESTRUCT*)LParam)->lpCreateParams);
    break;
    
/*****************
    case WM_MENUSELECT: {
      int N=1;
      ::MessageBeep(0);
    }  
    break;

    case WM_MENUCHAR: {
      int N=1;
    }  
    break;
******************/

    /*case WM_MENUSELECT: if ( LParam > 0 && (HIWORD(WParam) & (MF_POPUP)) > 0 ) {
      int Pos = LOWORD(WParam);
      ::HMENU HMenu = ::GetSubMenu( (::HMENU)LParam,Pos );
     
      if (!HMenu) {
        break;
      }
      
      ::MENUINFO Info; 
      Info.cbSize = sizeof(::MENUINFO); 
      Info.fMask = MIM_MENUDATA;// | MIM_STYLE;

      ::GetMenuInfo(HMenu,&Info); 
      TCommand *Cmd = (TCommand*)Info.dwMenuData;

      if (Cmd) {
        for (int N = 0; N < Cmd->Children.Count(); N++) {
          bool Enable = Cmd->Children.Get(N).TCommand_GetEnable();
          ::EnableMenuItem(
            HMenu,
            N,
            (Enable ? MF_BYPOSITION|MF_ENABLED : MF_BYPOSITION|MF_DISABLED|MF_GRAYED)
          );
        }
      }
      return 0;
    }
    break;*/

	
  //if (Msg == WM_INITDIALOG)
  //{
  //int N=1;
  //}
/***************  
    case WM_PARENTNOTIFY: switch (WParam)
    {
      case WM_CREATE:
        ::HWND HWndChild = (::HWND)LParam;
        char ClassName[50]; if (0 != ::GetClassName(HWndChild,ClassName,50))
        {
          if (0 == lstrcmpi(ClassName,"Edit"))
          {
            if (!TControlEdit::oldWndProc)
            {
              TControlEdit::oldWndProc = (::WNDPROC)::SetWindowLong(HWndChild,GWL_WNDPROC,(LONG)TControlEdit::WndProc);
              //return 0;
            }

            //TControlEdit *ControlEdit = (TControlEdit*)::GetWindowLong(HWndChild,GWL_USERDATA);
            
            //::SetWindowLong(HWndChild,GWL_USERDATA,(long)((CREATESTRUCT*)LParam)->lpCreateParams);

          }
        }
        
        int N=1;
      break;
    }
    break;
********************/    
  }
  
  if (Window) { 
    return Window->TWindow_WndProc(TMessage(Msg,WParam,LParam));
  }
  return ::DefWindowProc(HWnd,Msg,WParam,LParam);
}

//
BOOL CALLBACK TWindow::EnableWindows(HWND HWnd,LPARAM LParam) 
{
  TWindow *This = (TWindow*)LParam; if (This->hWnd != HWnd)
  {
    //TWindow *Window = (TWindow*)::GetWindowLong(HWnd,GWL_USERDATA); if (!Window->isModal)
      { ::EnableWindow(HWnd,true);}
  }
  return TRUE;
}

//
BOOL CALLBACK TWindow::DisableWindows(HWND HWnd,LPARAM LParam) 
{
  TWindow *This = (TWindow*)LParam; if (This->hWnd != HWnd)
    { ::EnableWindow(HWnd,false);}
  return TRUE;
}

// TControlEdit ///////////////////////////////////////////////////////////////

::WNDPROC TControlEdit::oldWndProc = NULL;

//
TControlEdit::TControlEdit(TWindow &Parent)
{
  // HELP: Using Window Procedures 
  //    MakeProcInstance
/******************
  if (!oldWndProc)
  {
    WNDCLASSEX WndClassEx; ::GetClassInfoEx(::GetModuleHandle(NULL),"Edit",&WndClassEx);
    oldWndProc = WndClassEx.lpfnWndProc;
    //WndClassEx.lpfnWndProc = WndProc;
    //WndClassEx.hInstance = ::GetModuleHandle(NULL);
    
    static char *CN = "Edit";
    WndClassEx.lpszClassName = CN;
    
    bool RR = ::UnregisterClass("Edit",::GetModuleHandle(NULL));
    RR = ::RegisterClassEx(&WndClassEx);
    RR=RR;
  }
******************/  

  hWnd = ::CreateWindowEx(
    0,
    "Edit"
    //"RICHEDIT_CLASS"
    ,NULL,
    WS_VISIBLE|WS_CHILD|/*WS_BORDER|*/WS_HSCROLL|WS_VSCROLL  
   |ES_MULTILINE|ES_AUTOHSCROLL|ES_AUTOVSCROLL
   //|ES_OEMCONVERT
    ,0,0,0,0,
    Parent.Handle(),NULL,::GetModuleHandle(NULL),this
  );
  
  oldWndProc = (::WNDPROC)::SetWindowLong(hWnd,GWL_WNDPROC,(LONG)WndProc);
  ::SetWindowLong(hWnd,GWL_USERDATA,(LONG)this);
  
  ::lstrcpy(sFont,"Courier New");
  //::lstrcpy(sFont,"Arial");
  hFont = ::CreateFont(
    20,0,0,0,FW_NORMAL,0/*Italic*/,0/*Underline*/,0/*StrikeOut*/,
    DEFAULT_CHARSET
    //ANSI_CHARSET
    //RUSSIAN_CHARSET
    //OEM_CHARSET
    ,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
    DEFAULT_PITCH|FF_DONTCARE,sFont
  );
  ::SendMessage(hWnd,WM_SETFONT,(WPARAM)hFont,0);  
}

//
TControlEdit::~TControlEdit()
{
  ::DeleteObject(hFont);
  ::DestroyWindow(hWnd); 
} 

//    
LRESULT TControlEdit::TControl_WndProc(TWindow::TMessage &Message)
{
  return ::CallWindowProc(oldWndProc,hWnd,Message.Msg,Message.WParam,Message.LParam);
  //return oldWndProc(hWnd,Message.Msg,Message.WParam,Message.LParam);
}

//
LRESULT CALLBACK TControlEdit::WndProc(HWND HWnd,UINT Msg,WPARAM WParam,LPARAM LParam)
{
  TControlEdit *Control = (TControlEdit*)::GetWindowLong(HWnd,GWL_USERDATA);

  //if (Msg == WM_CREATE)
  //  { ::SetWindowLong(HWnd,GWL_USERDATA,(long)((CREATESTRUCT*)LParam)->lpCreateParams);}

  if (Control) { 
    return Control->TControl_WndProc(TWindow::TMessage(Msg,WParam,LParam));
  }
  return ::CallWindowProc(oldWndProc,HWnd,Msg,WParam,LParam);
  //return oldWndProc(HWnd,Msg,WParam,LParam);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
using namespace svl::test;

//
LRESULT TWindowInfoTest::TWindow_WndProc(TMessage &Message)
{
  switch (Message.Msg)
  {
    case WM_SIZE:
    {
      ::MoveWindow(Edit.GetHandle(),0,0,Message.LParamLo(),Message.LParamHi(),true); 
    }
    break;
  }
  return TWindow::TWindow_WndProc(Message);
}

//
LRESULT TWindow1::TWindow_WndProc(TMessage &Message)
{
  switch (Message.Msg)
  {
    case WM_LBUTTONDOWN:
    {
      //::MessageBeep(0); 
    }
    break;

    case WM_RBUTTONDOWN:
    {
      ::MoveWindow(WindowInfo.Handle(),0,0,100,100,true); 
      WindowInfo.ShowModal();
    }
    break;
    
    case WM_MOUSEWHEEL:
    {
      ::MessageBeep(0);
      
      int Delta = GET_WHEEL_DELTA_WPARAM(Message.WParam);
      Delta=Delta;
    }
    break;
  }
  return TWindow::TWindow_WndProc(Message);
}

///////////////////////////////////////////////////////////////////////////////
void TestTWindow()
{
  TWindow1 Win; 
  ::MoveWindow(Win.Handle(),50,50,100,700,true); 
  Win.Show(); 
  Win.MessagesLoop();
}

//
void TestTPopupMenu()
{
  struct TPopupMenu
  {
    struct TItem
    {
      virtual void TItem_Click() = 0;
    };
    
    TPopupMenu() 
    { 
      hMenu = ::CreatePopupMenu();
      //MENUINFO MI; MI.fMask = MIM_STYLE; MI.dwStyle = MNS_NOTIFYBYPOS;
      //::SetMenuInfo(hMenu,&MI);
    }
   ~TPopupMenu() { ::DestroyMenu(hMenu);}
    //
    void AddItem(char *Name,TItem *Item = NULL)
    {
      ::AppendMenu(hMenu, MF_STRING, (UINT_PTR)Item, Name );
    }
    void AddMenu(TPopupMenu &Menu,char *Name)
    {
      ::AppendMenu(hMenu, MF_POPUP, (UINT_PTR)Menu.hMenu ,Name);
    }

    //
    void Popup(::HWND HWnd,int X,int Y)
    {
      TItem *Item = (TItem *)::TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON, X,Y, 0, HWnd, NULL); 
      if (Item) { Item->TItem_Click();}
    }

  private:
    ::HMENU hMenu;
  };

  struct TWindow1 : public svl::TWindow
  {    
    virtual LRESULT TWindow_WndProc(TMessage &Message)
    {
      switch (Message.Msg)
      {
        case WM_RBUTTONDOWN:
        {
          struct TItem : public TPopupMenu::TItem
          {
            virtual void TItem_Click()
            {
              ::MessageBeep(0);
            }
          }
          Item;
          
          char *Item1 = "Item1";
          char *Item2 = "Item2";
          char *Item3 = "Item3";
          char *SMenu1 = "Menu1";
          char *Sep = "-";
          
          TPopupMenu Menu1;
            Menu1.AddItem(Item1);
            Menu1.AddItem(Sep);
            Menu1.AddItem(Item3,&Item);

          TPopupMenu Menu;
            Menu.AddItem(Item1);
            Menu.AddItem(Item2);
            Menu.AddItem(Item3);
            Menu.AddMenu(Menu1,SMenu1);

          Menu.Popup(Handle(),10,10);  
        }
        break;
        
        case WM_COMMAND:
        {
          int N=1;
        }
        break;
      }
      return TWindow::TWindow_WndProc(Message);
    }
  };

  TWindow1 Win; 
  ::MoveWindow(Win.Handle(),50,50,100,700,true); 
  Win.Show(); 
  Win.MessagesLoop();
}
